<template>
	<view>
		<view>聊天：在线人数：{{count}}</view>
		<view class="chat-box" v-html="allmsg"></view>
		<input v-model="msg" />
		<button @click="sendMsg">发送</button>
		<button @click="exitChat">退出聊天</button>
	</view>
</template>

<script>
	import io from 'socket.io-client';
	export default {
		data() {
			return {
				allmsg: "",
				msg: "",
				count: 0,
				socket: null,

				socketOpen: false,
				socketMsgQueue: ['你好', '我好', '大家好', '世界和平', '你好', '我好', '大家好', '世界和平']
			}
		},
		beforeDestroy() {
			// 在页面销毁前断开socket连接
			if (this.socket) {
				this.socket.disconnect();
			}
		},
		onLoad() {
			// #ifdef H5
			// this.onSocketTask();
			// #endif
			this.ws();
			// console.log(this.postStreamList());
			// this.fetchStreamedResponse('送啥！');
			// return;
		},
		methods: {
			// 建立websocket连接
			onSocketTask() {
				const socketTask = uni.connectSocket({
					url: 'ws://localhost:3001',
					success(e) {
						console.log("socketTask =>success", e);
					}
				});
				console.log("socketTask", socketTask);
				// WebSocket连接打开 执行的事件
				this.socketMsgQueue = ['你好', '我好', '大家好', '世界和平'];
				uni.onSocketOpen((res) => {
					console.log('WebSocket连接已打开！');
					this.socketOpen = true;
					let i = 0;
					let timer = setInterval(() => {
						i++;
						if (this.socketMsgQueue && i < this.socketMsgQueue.length) {
							// 发送消息
							var msg = this.socketMsgQueue[i];
							if (this.socketOpen) {
								uni.sendSocketMessage({
									data: msg,
									success: res => {
										this.$notify.show({
											type: 'success',
											text: msg + ', 您有新的订单，请注意查收！'
										});
										console.log('发送消息-success', res);
									},
									fail: e => {
										console.error('发送消息-fail', e);
									}
								});
							} else {
								this.socketMsgQueue.push(msg);
							}
						} else {
							clearInterval(timer);
							this.socketMsgQueue = [];
						}
					}, 3000);
				});

				uni.onSocketError(res => {
					uni.showToast({
						title: 'WebSocket连接打开失败，请检查',
						icon: 'none'
					});
					console.log('WebSocket连接打开失败，请检查！');
				});
				uni.onSocketClose(res => {
					console.log('WebSocket 已关闭！');
				});
				// 收到服务器内容
				uni.onSocketMessage(res => {
					console.log('收到服务器内容：' + res.data);
				});
			},

			connectSocke() {
				const io = require('socket.io-client');
				console.log(require('socket.io-client/package.json').version);
				const socketTask = uni.connectSocket({
					url: "ws://localhost:3001/socketTest",
					header: {
						'Authorization': `Bearer `,
						'content-type': 'application/json'
					},
					transports: ['websocket', 'polling'],
					success(e) {
						console.log("socketTask =>success", e);
					}
				});
				console.log("socketTask", socketTask);

				uni.onSocketOpen(() => {
					console.log("服务器已经打开链接");
					// ws.send("大家好，我是新来的");

					uni.sendSocketMessage({
						data: JSON.stringify({
							text: "大家好，我是通过uni来的",
							to: 'socket', // 接收者的用户ID
							token: this.vuex_token, // 接收者的用户ID
						})
					})
				})

				uni.onSocketMessage((res) => {
					console.log('收到服务器内容：' + res.data);
					// this.allmsg += `<view>${res.data}</view>`;

					const obj = JSON.parse(res.data);
					if (obj.status == "msg") {
						console.log("typeof obj.content", typeof obj.content);
						console.log("obj.content", obj.content);
						this.allmsg += `<view>${this.blobToStr(obj.content.data)}</view>`;

					} else if (obj.status === "count") {
						console.log("obj.count", obj.count);
						this.count = obj.count;
					}
				})
			},
			ws() {
				var mid = uni.$uv.guid(10);
				this.socket = io(this.vuex_user.baseUrl, {
					query: {
						mid: mid
					},
					secure: true,
					rejectUnauthorized: false,
					auth: {
						authorization: "Bearer " + this.vuex_token
					},
					transports: ['websocket', 'polling'],
				});
				this.socket.on('connect', () => {
					console.log('ws 已连接');
					// 连接建立后，可以进行事件监听或数据发送操作
					// this.socket.emit('send_data', {
					// 	time: +new Date()
					// });
				});

				// 监听服务器推送的消息
				this.socket.on('message', (msg) => {
					console.log('ws 收到服务器消息：', msg);
				});
				// 监听服务器推送的消息
				this.socket.on(mid, (msg) => {
					uni.$uv.toast('ws ' + msg);
				});

				// 监听错误事件
				this.socket.on('error', (msg) => {
					console.log('ws error', msg);
				});
			},
			resDelChat(index) {
				if (this.data.length == 1) {
					let array = this.vuex_chat;
					let index = array.findIndex(item => item.id === this.vuex_chat_id);
					let newArray = array.slice();
					newArray.splice(index, 1);
					this.$uv.vuex('vuex_chat', newArray);
				}
				this.data.splice(index, 1);
			},
			async taskd() {
				var that = this;
				if (that.chat) {
					this.$refs.toast.show({
						message: "发送中。。。",
						duration: '2000'
					});
					var con = JSON.parse(JSON.stringify(this['config_' + this.tabbarsValue]), true);
					const res = JSON.parse(JSON.stringify(this.data), true);
					const data = res.map(({
						role,
						content
					}) => ({
						role,
						content
					}));
					var dfds = {
						role: 'user',
						type: "text",
						content: this.chat,
						createdAt: new Date(),
					}
					if (con['messages']) {
						con['messages'] = [...con.messages, ...this.data, dfds];
					} else {
						con['messages'] = [...this.data, dfds];
					}
					let sss = {};
					sss['messages'] = [...con.messages, ...this.data, dfds];
					sss['model'] = con['model'];
					// '/v1/chat/completions'
					const requestTask = await api(this.aiApi + '/stream', sss, {
						custom: {
							auth: true,
							toast: true,
							catch: true,
						},
						// enableChunked: true, // 开启流传输
						// // 设置流式接收数据
						// streaming: true,
						// withCredentials: true,
						// 接收数据的回调函数
						getTask: (task, options) => {
							console.log('response =>', task, options)
							// 这里监听消息
							options.onChunkReceived = (res) => {
								let decoder = new TextDecoder('utf-8');
								let text = decoder.decode(new Uint8Array(res.data));
								console.log(text)
							};
							// 相当于设置了请求超时时间500ms
							task._xhr.onreadystatechange = function(e) {
								// console.log('onreadystatechange =>', task._xhr.responseText)
								if (task._xhr.readyState === XMLHttpRequest.LOADING) {
									// 处理 HTTP 数据块
									console.log('response =>', new Uint8Array(task._xhr.responseText))
									// const decoder = new TextDecoder('utf-8'); // 创建一个utf-8解码器，用于解码二进制数据为文本。
									// const txt = decoder.decode(e.data); // 解码二进制数据为文本。
									// const a = parseStream(txt)
									// console.log(txt); // 打印解码后的文本数据。
									// const uint8Array = new Uint8Array(task._xhr.response);
									// console.log(uint8Array);
									// let text = String.fromCharCode.apply(null, uint8Array);
									// console.log(text);
									// text = decodeURIComponent(escape(text));
									// console.log(text);

									// const data = JSON.parse(resp._xhr.responseText);
									// 	// 获取content。从浏览器的控制台中可以看到服务器返回的数据，里面的内容就在choices下面的delta中的content里。如果content为空，则给一个空的字符串
									// 	const {content = ''} = data.choices[0].delta;
									// 	console.log(content);
									// console.log('response =>', resp._xhr.response)
								}
							};
						},
					}).then(e => {
						e = e.data;
						console.log(e);
						if (e && e.choices) {
							if (this.vuex_chat[0] && this.vuex_chat[0].text == 'New Chat') {
								this.vuex_chat.splice(index, 1);
							}
							this.data.push(dfds);
							this.chat = null;
							// for (var i = 0; i < e.choices.length; i++) {
							// 	// e.choices[i].message['createdAt'] = e['created'];
							// 	e.choices[i].message['type'] = 'text';
							// 	this.data.push(e.choices[i].message);
							// }
						}
					}).catch(e => {
						console.log(e);
						that.$refs.toast.show({
							type: 'error',
							message: e.msg || "发送失败！",
							duration: '2000'
						});
					}).finally(e => {
						console.log('finally', e);
					})

				} else {
					that.$refs.toast.show({
						type: 'error',
						message: "要提问的内容为空！"
					})
				}
			},
			async postStreamList() {
				return new Promise(async (resolve, reject) => {
					const requestOptions = {
						method: 'POST',
						headers: {
							'Content-Type': 'application/json'
						},
						body: JSON.stringify({
							"model": "gpt-3.5-turbo",
							"messages": [{
								"role": "assistant",
								"content": "how are you"
							}]
						})
					};
					let count = 0;
					const streamResponse = await fetch('/dpc/ttapi/chat', requestOptions);
					const reader = streamResponse.body.getReader();
					let errText = "";
					const read = () => {
						return reader.read().then(({
							done,
							value
						}) => {
							count++;
							if (done) {
								console.log("victor react reviced: end");
								resolve(ENDTEXT);
								return;
							}

							const textDecoder = new TextDecoder();
							console.log("返回的数据：", textDecoder.decode(value));
							let text = "";
							const strArr = (errText + textDecoder.decode(value)).split(
								"data: ");
							console.log("解析字符", textDecoder.decode(value))
							if (strArr) {
								for (let i = 0; i < strArr.length; i++) {
									let json = {};
									if (strArr[i] && strArr[i] !== "[DONE]") {
										try {
											json = JSON.parse(strArr[i]);
											if (json.choices.length && json.choices[0].delta
												.content) {
												text = text + json.choices[0].delta.content;
											}
											errText = "";
										} catch (e) {
											console.log("出错", strArr[i])
											errText = strArr[i];
										}

									}
								}
								resolve(text);
							}
							return read();
						});
					}
					read();
				});
			},
			requestChat(msg) {
				// 在页面中创建 XMLHttpRequest 对象
				var xhr = new XMLHttpRequest()
				// 设置 XMLHttpRequest 对象
				xhr.open('get', 'http://localhost:3000/ttapi/chat?messages=' + msg.messages)
				xhr.responseType = 'text'
				xhr.header = {
					'Authorization': "Bearer " + this.vuex_token
				}
				xhr.timeout = 0
				xhr.onreadystatechange = function() {
					if (xhr.readyState === XMLHttpRequest.LOADING) {
						// 处理 HTTP 数据块
						console.log(xhr.responseText)
					}
				}
				xhr.send()
			},
			async fetchStreamedResponse(message) {
				var messages = [{
					'role': 'user', // 用户角色，可以是user,assistant,system,function等，具体可以参考openai文档。
					'content': `${message}`, // 用户输入的内容，可以是文本，也可以是json格式。
				}];
				const content = {
					"chatId": "111",
					"stream": true,
					"model": 'gpt-4o-mini',
					"messages": JSON.stringify(messages)
				}
				// 假设已经完成了封装,并进行了导入  
				// const resp = await this.requestChat(content);
				const resp = await this.streamRequest(content);
				// console.log(resp._xhr);
				// console.log(resp.XMLHttpRequest);
				// // 返回请求头信息
				// console.log(resp);

				resp._xhr.onreadystatechange = function(e) {
					if (resp._xhr.readyState === XMLHttpRequest.LOADING) {
						// 处理 HTTP 数据块
						console.log('response =>', resp._xhr.responseText)
						// const uint8Array = new Uint8Array(resp._xhr.responseText);
						//     let text = String.fromCharCode.apply(null, uint8Array);
						//     text = decodeURIComponent(escape(text));
						//     console.log(text);
						// const data = JSON.parse(resp._xhr.responseText);
						// 	// 获取content。从浏览器的控制台中可以看到服务器返回的数据，里面的内容就在choices下面的delta中的content里。如果content为空，则给一个空的字符串
						// 	const {content = ''} = data.choices[0].delta;
						// 	console.log(content);
						// console.log('response =>', resp._xhr.response)
					}
				};

				// // 成功回调 返回流传输信息 返回arrayBuffer
				// resp.responseText((e) => {
				// 	// 进行处理二进制编码
				// 	const decoder = new TextDecoder('utf-8'); // 创建一个utf-8解码器，用于解码二进制数据为文本。
				// 	const txt = decoder.decode(e.data); // 解码二进制数据为文本。
				// 	const a = parseStream(txt)
				// 	console.log(a); // 打印解码后的文本数据。
				// })
			},
			async postStreamList() {
				return new Promise(async (resolve, reject) => {
					const requestOptions = {
						method: 'POST',
						headers: {
							'Content-Type': 'application/json'
						},
						body: JSON.stringify({
							"model": "gpt-3.5-turbo",
							"messages": [{
								"role": "assistant",
								"content": "how are you"
							}]
						})
					};
					let count = 0;
					const streamResponse = await fetch('/dpc/ttapi/chat', requestOptions);
					const reader = streamResponse.body.getReader();
					let errText = "";
					const read = () => {
						return reader.read().then(({
							done,
							value
						}) => {
							count++;
							if (done) {
								console.log("victor react reviced: end");
								resolve(ENDTEXT);
								return;
							}

							const textDecoder = new TextDecoder();
							console.log("返回的数据：", textDecoder.decode(value));
							let text = "";
							const strArr = (errText + textDecoder.decode(value)).split(
								"data: ");
							console.log("解析字符", textDecoder.decode(value))
							if (strArr) {
								for (let i = 0; i < strArr.length; i++) {
									let json = {};
									if (strArr[i] && strArr[i] !== "[DONE]") {
										try {
											json = JSON.parse(strArr[i]);
											if (json.choices.length && json.choices[0].delta
												.content) {
												text = text + json.choices[0].delta.content;
											}
											errText = "";
										} catch (e) {
											console.log("出错", strArr[i])
											errText = strArr[i];
										}

									}
								}
								resolve(text);
							}
							return read();
						});
					}
					read();
				});
			},
			exitChat() {
				uni.closeSocket();
			},
			blobToStr(data) {
				var enc = new TextDecoder("utf-8");
				var arr = new Uint8Array(data);
				return enc.decode(arr)
			},
			sendMsg() {
				this.socket.emit('send_data', {
					time: +new Date()
				});
			}
		}
	}
</script>

<style scoped>
	.chat-box {
		width: 100%;
		height: 800rpx;
		border: 1px solid red;
	}
</style>